/*
 *    Copyright (c) 2018-2025, boss All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the boss developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: boss
 */
package com.hopes.bizz.emergency.drill.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hopes.bizz.common.core.util.DateUtils;
import com.hopes.bizz.emergency.drill.dto.ErEmergencyDrillDTO;
import com.hopes.bizz.emergency.drill.entity.ErActualDrillEntity;
import com.hopes.bizz.emergency.drill.entity.ErDrillPlanEntity;
import com.hopes.bizz.emergency.drill.mapper.ErDrillPlanMapper;
import com.hopes.bizz.emergency.drill.service.ErActualDrillService;
import com.hopes.bizz.emergency.drill.service.ErDrillPlanService;
import com.hopes.bizz.emergency.drill.vo.ErEmergencyDrillVO;
import com.hopes.bizz.emergency.plan.entity.ErEmergencyPlanEntity;
import com.hopes.bizz.emergency.plan.vo.ErEmergencyPlanVO;
import com.hopes.boss.common.core.util.R;
import com.hopes.boss.common.entity.BaseEntity;
import com.hopes.boss.common.security.util.SecurityUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ReflectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.ToLongFunction;
import java.util.stream.Collectors;

/**
 * 应急演练计划
 *
 * @author cx
 * @date 2023-11-06 14:27:42
 */
@Service
public class ErDrillPlanServiceImpl extends ServiceImpl<ErDrillPlanMapper, ErDrillPlanEntity> implements ErDrillPlanService {
    @Resource
    private  ErActualDrillService erActualDrillService;
    @Override
    public Page<ErEmergencyDrillVO> getDrillOverviewPage(Page page, ErEmergencyDrillDTO dto ) {
        Integer year = dto.getYear();
        // 只统计当年一整年的数据
        Date beginTime = null;
        Date endTime = null;
        if (Objects.nonNull(year)){
             beginTime = DateUtils.parseDate(year + "-01-01", "yyyy-MM-dd");
             endTime = DateUtils.parseDate(year + "-12-31", "yyyy-MM-dd");
        }


        IPage<ErDrillPlanEntity> planDrillPage = this.page(page, Wrappers.<ErDrillPlanEntity>lambdaQuery()
                .eq(Objects.nonNull(dto.getOrgId()), ErDrillPlanEntity::getOrgId, dto.getOrgId())
                .ge(Objects.nonNull(beginTime),ErDrillPlanEntity::getPlanDrillTime, beginTime)
                .le(Objects.nonNull(endTime),ErDrillPlanEntity::getPlanDrillTime, endTime));


        List<ErActualDrillEntity> actualDrillList = erActualDrillService.list(Wrappers.<ErActualDrillEntity>lambdaQuery()
                .eq(Objects.nonNull(dto.getOrgId()), ErActualDrillEntity::getOrgId, dto.getOrgId())
                .ge(Objects.nonNull(beginTime),ErActualDrillEntity::getDrillBeginTime, beginTime)
                .le(Objects.nonNull(endTime),ErActualDrillEntity::getDrillBeginTime, endTime));

        //对planId去重
        List<ErActualDrillEntity> distinctActualDrillList = actualDrillList.stream()
                .collect(Collectors.toMap(ErActualDrillEntity::getDrillPlanId, er -> er, (existing, replacement) -> existing))
                .values()
                .stream()
                .collect(Collectors.toList());


        Map<Long, ErEmergencyDrillVO> resultMap = new HashMap<>();
        for (ErDrillPlanEntity planDrill : planDrillPage.getRecords()) {
            Long orgId = planDrill.getOrgId();
            if (!resultMap.containsKey(orgId)) {
                ErEmergencyDrillVO vo = new ErEmergencyDrillVO();
                vo.setOrgId(orgId);
                vo.setPlanDrillCount(0L);
                vo.setRealDrillCount(0L);
                vo.setDistinctRealDrillCount(0L);
                // 初始化计数器Map
                resultMap.put(orgId, vo);
            }
            ErEmergencyDrillVO vo = resultMap.get(orgId);
            // 总数加一
            vo.setPlanDrillCount(vo.getPlanDrillCount() + 1);
        }
        //统计真实演练数
        setActualCount(actualDrillList, resultMap, (vo, orgId) -> vo.setRealDrillCount(vo.getRealDrillCount() + 1));
        //统计真实演练数-去重（用于计算对应任务完成率）
        setActualCount(distinctActualDrillList, resultMap, (vo, orgId) -> vo.setDistinctRealDrillCount(vo.getDistinctRealDrillCount() + 1));
        List<ErEmergencyDrillVO> resultList = new ArrayList<>(resultMap.values());
        for (ErEmergencyDrillVO vo : resultList) {
            Long planDrillCount = vo.getPlanDrillCount();
            Long distinctRealDrillCount = vo.getDistinctRealDrillCount();

            if (planDrillCount != null && planDrillCount != 0) {
                // 计算并设置 finishRate 保留两位小数
                double finishRate = (double) distinctRealDrillCount / planDrillCount;
                // 保留两位小数
                finishRate = Math.round(finishRate * 100.0) / 100.0;
                vo.setFinishRate(finishRate);
            } else {
                // 处理 planDrillCount 为0的情况
                vo.setFinishRate(0.0);
            }
        }
        Page<ErEmergencyDrillVO> resultPage = new Page<>();
        resultPage.setRecords(resultList);
        resultPage.setCurrent(planDrillPage.getCurrent());
        resultPage.setSize(planDrillPage.getSize());
        resultPage.setTotal(planDrillPage.getTotal());
        return resultPage;
    }

    /**
     * 不同字段统计
     * @param drillList
     * @param resultMap
     * @param countUpdater
     */
    private static void setActualCount(List<ErActualDrillEntity> drillList, Map<Long, ErEmergencyDrillVO> resultMap, BiConsumer<ErEmergencyDrillVO, Long> countUpdater) {
        for (ErActualDrillEntity drill : drillList) {
            Long orgId = drill.getOrgId();
            if (!resultMap.containsKey(orgId)) {
                ErEmergencyDrillVO vo = new ErEmergencyDrillVO();
                vo.setOrgId(orgId);
                vo.setPlanDrillCount(0L);
                vo.setRealDrillCount(0L);
                vo.setDistinctRealDrillCount(0L);
                // 初始化计数器Map
                resultMap.put(orgId, vo);
            }
            ErEmergencyDrillVO vo = resultMap.get(orgId);
            countUpdater.accept(vo, orgId);
        }
    }


}